package com.gitee.minimalismstyle.fresh.simple.api.service.impl

import com.gitee.minimalismstyle.fresh.common.api.OssApi
import com.gitee.minimalismstyle.fresh.common.core.config.FreshProperties
import com.gitee.minimalismstyle.fresh.common.core.const.DefaultConst
import com.gitee.minimalismstyle.fresh.common.core.domain.*
import com.gitee.minimalismstyle.fresh.common.data.beetl.extra.toPageRequest
import com.gitee.minimalismstyle.fresh.common.data.beetl.extra.toQueryBody
import com.gitee.minimalismstyle.fresh.simple.api.service.*
import com.github.liaochong.myexcel.core.DefaultStreamExcelBuilder
import com.github.liaochong.myexcel.core.templatehandler.BeetlTemplateHandler
import com.github.liaochong.myexcel.utils.AttachmentExportUtil
import org.beetl.sql.core.SQLManager
import org.beetl.sql.core.SQLSource
import org.beetl.sql.core.SqlId
import org.beetl.sql.core.page.PageRequest
import org.beetl.sql.core.page.PageResult
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.nio.file.Path
import java.util.concurrent.Executors
import javax.servlet.http.HttpServletResponse


@Service
class SimpleServiceImpl : SimpleService {

    @Autowired
    private lateinit var sm: SQLManager

    @Autowired
    private lateinit var simpleSqlService: SimpleSqlService

    @Autowired
    private lateinit var simpleListService: SimpleListService
    @Autowired
    private lateinit var simpleListFieldService: SimpleListFieldService

    @Autowired
    private lateinit var ossApi: OssApi

    @Autowired
    private lateinit var redisTemplate: StringRedisTemplate

    @Autowired
    private lateinit var freshProperties: FreshProperties

    @Autowired
    private lateinit var snowflakeIdWorker: SnowflakeIdWorker
    @Autowired
    private lateinit var response: HttpServletResponse


    override fun find(code: String, params: QueryParams<Simple>): R<QueryBody<Simple>> {
        val simpleSqlParams = simpleListService.getSimpleSqlParams(code, params.params!!).get()
        val pageRequest: PageRequest<Simple> = params.toPageRequest()
        val page = sm.executePageQuery(simpleSqlParams.sql, Simple::class.java, params.params, pageRequest)
        return R.success(page.toQueryBody())
    }

    override fun export(code: String, params: QueryParams<Simple>) {
        val id = snowflakeIdWorker.nextId()
        val tempdir = freshProperties.tempdir.replaceFirst("classes:", this.javaClass.getResource("/").path)
        val tempPath = "$tempdir/import/$id.xlsx"
        val simpleList = simpleListService.findByCode(code).get()
        val simpleListFields = simpleListFieldService.findByListId(simpleList.id!!).get(listOf())
        val simpleSqlParams = simpleListService.getSimpleSqlParams(code, params.params!!).get()
        params.pageSize = 1000
        val dataMap: MutableMap<String, Any> = mutableMapOf()
        dataMap["simpleListFields"] = simpleListFields
        DefaultStreamExcelBuilder
                .of(Simple::class.java) // 如导出Map类型数据，请使用of(Map.class)
                .threadPool(Executors.newFixedThreadPool(10)) // 线程池，可选
                .templateHandler(BeetlTemplateHandler::class.java) // 追加模板数据，可选，适合极度个性化数据导出
                .capacity(10000) // 容量设定，在主动划分excel使用，可选
                .start().use { streamExcelBuilder ->
                    var pageRequest: PageRequest<Simple> = params.toPageRequest()
                    var pageResult: PageResult<Simple> = sm.executePageQuery(simpleSqlParams.sql, Simple::class.java, params.params, pageRequest)
                    val totalPage = pageResult.totalPage
                    streamExcelBuilder.append("export/simpleTitle.btl", dataMap)
                    streamExcelBuilder.append (pageResult.list)
                    for (i in 1..totalPage){
                        params.pageNumber = i
                        pageRequest = params.toPageRequest()
                        pageResult = sm.executePageQuery(simpleSqlParams.sql, Simple::class.java, params.params, pageRequest)
                        streamExcelBuilder.append (pageResult.list)

                    }
                    val zip: Path = streamExcelBuilder.buildAsZip("test")
                    AttachmentExportUtil.export(zip, "finalName.zip", response)
                }


       /* val file = File(tempPath)
        val result = ossApi.save(file.toMultipartFile()).get(mapOf())
        val exportStatus = ExportStatus()
        exportStatus.fileId = result["id"] as Long
        redisTemplate.opsForValue().set("IMPORT_$id", exportStatus)*/

    }

    override fun findByQueryParams(code: String, params: QueryParams<Simple>): R<QueryBody<Simple>> {
        params.params?.put(DefaultConst.SQL_PARAM_NAME, code)
        return this.findByQueryParams(params)
    }


    override fun findOne(code: String, params: QueryParams<Simple>): R<Simple> {
        params.params?.put(DefaultConst.SQL_PARAM_NAME, code)
        return this.findOne(params)
    }

    override fun findAll(code: String, params: QueryParams<Simple>): R<List<Simple>> {
        params.params?.put(DefaultConst.SQL_PARAM_NAME, code)
        return this.findAll(params)
    }


    @Transactional
    override fun update(code: String, simple: Simple): R<Simple> {
        simple[DefaultConst.SQL_PARAM_NAME] = code
        return this.update(simple)
    }

    @Transactional
    override fun insert(code: String, simple: Simple): R<Simple> {
        simple[DefaultConst.SQL_PARAM_NAME] = code
        return this.update(simple)
    }

    @Transactional
    override fun delete(code: String, simple: Simple): R<Simple> {
        simple[DefaultConst.SQL_PARAM_NAME] = code
        return this.update(simple)
    }

    private fun findOne(params: QueryParams<Simple>): R<Simple> {
        val sqlId = getSqlId(params.params?.get(DefaultConst.SQL_PARAM_NAME).toString())
        return R.success(sm.selectSingle(sqlId, params.params, Simple::class.java))
    }

    private fun findAll(params: QueryParams<Simple>): R<List<Simple>> {
        val sqlId = getSqlId(params.params?.get(DefaultConst.SQL_PARAM_NAME).toString())
        return R.success(sm.select(sqlId, Simple::class.java, params.params))
    }

    private fun findByQueryParams(params: QueryParams<Simple>): R<QueryBody<Simple>> {
        val sqlId = getSqlId(params.params?.get(DefaultConst.SQL_PARAM_NAME).toString())
        val pageRequest: PageRequest<Simple> = params.toPageRequest()
        return R.success(sm.pageQuery(sqlId, Simple::class.java, params.params, pageRequest).toQueryBody())
    }

    private fun update(simple: Simple): R<Simple> {
        val sqlId = getSqlId(simple[DefaultConst.SQL_PARAM_NAME].toString())
        sm.update(sqlId, simple)
        return R.success(simple)
    }

    private fun getSqlId(sqlCode: String): SqlId {
        val sql = simpleSqlService.findSqlByCode(sqlCode)
        var sqlId = SqlId.of("simple", sqlCode)
        if (!sm.isProduct || !sm.sqlLoader.exist(sqlId)) {
            var source = SQLSource(sqlId, sql.get())
            sm.sqlLoader.addSQL(sqlId, source)
        }
        return sqlId
    }

}